package com.sxhuayuan.parking.plugin.partnerpay;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.Map;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.druid.util.StringUtils;
import com.sxhuayuan.parking.compenent.Message;
import com.sxhuayuan.parking.config.PartnerpayScene;
import com.sxhuayuan.parking.config.Platform;
import com.sxhuayuan.parking.entity.OemConfig;
import com.sxhuayuan.parking.entity.ParkingIn;
import com.sxhuayuan.parking.entity.ParkingLot;
import com.sxhuayuan.parking.exception.MyException;
import com.sxhuayuan.parking.plugin.partnerpay.req.PayApplyReq;
import com.sxhuayuan.parking.plugin.partnerpay.result.JumpToSignPageResult;
import com.sxhuayuan.parking.plugin.partnerpay.result.NoticeInResult;
import com.sxhuayuan.parking.plugin.partnerpay.result.PayApplyResult;
import com.sxhuayuan.parking.plugin.partnerpay.result.QueryStateResult;
import com.sxhuayuan.parking.service.OemConfigService;
import com.sxhuayuan.parking.service.ParkingLotService;
import com.sxhuayuan.parking.utils.BeanUtils;
import com.sxhuayuan.parking.utils.DateUtils;
import com.sxhuayuan.parking.utils.DeviceUtil;
import com.sxhuayuan.parking.utils.SettingUtils;
import com.sxhuayuan.parking.utils.SpringUtils;

import weixin.popular.api.PayVeticleAPI;
import weixin.popular.bean.vehicle.EntranceNotification;
import weixin.popular.bean.vehicle.EntranceNotificationResult;
import weixin.popular.bean.vehicle.NavigateToAppForAuth;
import weixin.popular.bean.vehicle.PayApply;
import weixin.popular.bean.vehicle.PlateNumberInfo;
import weixin.popular.bean.vehicle.QueryState;
import weixin.popular.bean.vehicle.SceneInfo;

@Service("weixinPartnerpayApiServiceImpl")
public class WeixinPartnerpayApiServiceImpl extends PartnerpayApiService {

	Logger log = LoggerFactory.getLogger(getClass());
	static final String TIME_FORMAT = "yyyyMMddHHmmss";

	@Resource(name = "parkingLotServiceImpl")
	ParkingLotService lotService;
	@Resource(name = "oemConfigServiceImpl")
	OemConfigService oemConfigService;

	@Override
	public boolean isEnabled() {
		return true;
	}

	@Override
	public QueryStateResult queryUserState(ParkingLot lot, String openid, String subOpenid, String carPlate, String jumpScene) {
		OemConfig oem = oemConfigService.findByParkingLot(lot.getId());
		QueryState query = new QueryState();
		query.setAppid(oem.getWxAppid());
		query.setMch_id(oem.getWxMchid());
		query.setSub_appid(oem.getWxSubAppid());
		query.setSub_mch_id(oem.getWxSubMchid());
		query.setNonce_str(RandomStringUtils.randomAlphanumeric(8));
		query.setSign_type("HMAC-SHA256");
		query.setTrade_scene(PartnerpayScene.PARKING.name());
		if (!StringUtils.isEmpty(jumpScene)) {
			query.setJump_scene(jumpScene.toUpperCase());
		}
		if (!StringUtils.isEmpty(openid)) {
			query.setOpenid(openid);
		} else if (!StringUtils.isEmpty(subOpenid)) {
			query.setSub_openid(subOpenid);
		} else if (!StringUtils.isEmpty(carPlate)) {
			query.setPlate_number(carPlate);
		} else {
			Assert.notNull(null, "openid, subOpenid, carPlate 必须填一个");
		}
		weixin.popular.bean.vehicle.QueryStateResult queryResult = PayVeticleAPI.queryState(query, oem.getWxMchKey());
		QueryStateResult resp = new QueryStateResult(Platform.weixin);
		resp.setAppid(oem.getWxAppid());
		resp.setSubAppid(oem.getWxSubAppid());
		if (queryResult == null) {
			resp.setMsg("请求失败");
		} else if (!queryResult.isSuccess()) {
			resp.setMsg(queryResult.getReturn_msg());
		} else if (!"SUCCESS".equals(queryResult.getResult_code())) {
			resp.setMsg(queryResult.getErr_code_des());
		} else {
			resp.setOpenid(queryResult.getOpenid());
			resp.setSubOpenid(queryResult.getSub_openid());
			resp.setPath(queryResult.getPath());
			resp.setUserState(queryResult.getUser_state());
			if (queryResult.getPlate_number_info() != null) {
				resp.setCarPlates(queryResult.getPlate_number_info().stream().map(PlateNumberInfo::getPlate_number).collect(Collectors.toList()));
			}
			resp.setIsResultSuccess(true);
		}
		return resp;
	}

	@Override
	public Platform getPlatform() {
		return Platform.weixin;
	}

	@Override
	public NoticeInResult noticeIn(ParkingIn in) {
		EntranceNotification notification = new EntranceNotification();
		ParkingLot lot = lotService.findById(in.getParkingLotId());
		OemConfig oem = oemConfigService.findByParkingLot(in.getParkingLotId());
		String key = oem.getWxMchKey();
		notification.setSign_type("HMAC-SHA256");
		notification.setAppid(oem.getWxAppid());
		notification.setMch_id(oem.getWxMchid());
		notification.setSub_appid(oem.getWxSubAppid());
		notification.setSub_mch_id(oem.getWxSubMchid());
		notification.setNonce_str(RandomStringUtils.randomAlphanumeric(8));
		notification.setTrade_scene(PartnerpayScene.PARKING.name());
		SceneInfo sceneInfo = new SceneInfo();
		sceneInfo.setPlate_number(in.getCarPlate());
		sceneInfo.setStart_time(DateUtils.format(in.getInTime(), DateUtils.YYYYMMDDHHMMSS));
		sceneInfo.setParking_name(lot.getName());
		// 秒
		sceneInfo.setFree_time("0");
		sceneInfo.setNotify_url(getStateChangeNotifyUrl(PartnerpayScene.PARKING));
		notification.setScene_info(sceneInfo);
		EntranceNotificationResult result = PayVeticleAPI.entranceNotification(notification, key);
		if ("SYSTEMERROR".equals(result.getErr_code())) {
			result = PayVeticleAPI.entranceNotification(notification, key);
		}
		NoticeInResult resp = new NoticeInResult();
		if (!result.isSuccess()) {
			resp.setMsg(result.getReturn_msg());
		} else if (!"SUCCESS".equals(result.getResult_code())) {
			resp.setMsg(result.getErr_code_des());
		} else {
			resp.setIsResultSuccess(true);
			resp.setOpenid(result.getOpenid());
			resp.setUserState(result.getUser_state());
			resp.setSubOpenid(result.getSub_appid());
			resp.setAppid(result.getAppid());
			resp.setSubAppid(result.getSub_appid());
		}
		return resp;
	}

	/**
	 * 车牌状态变更时的回调地址
	 * 
	 * @return
	 */
	private String getStateChangeNotifyUrl(PartnerpayScene scene) {
		return SettingUtils.get().getSiteUrl() + "/common/partnerpay/wx/onstatechange/scene/" + scene.name().toLowerCase();
	}

	/**
	 * 支付结果回调通知地址
	 * 
	 * @return
	 */
	private String getPayResultNotifyUrl() {
		return SettingUtils.get().getSiteUrl() + "/common/partnerpay/wx/traderesult";
	}

	@Override
	public PayApplyResult payApply(PayApplyReq req) {
		PayApply apply = new PayApply();
		apply.setSign_type("HMAC-SHA256");
		apply.setAppid(req.getAppid());
		apply.setMch_id(req.getMchid());
		apply.setSub_appid(req.getSubAppid());
		apply.setSub_mch_id(req.getSubMchid());
		apply.setNonce_str(RandomStringUtils.randomAlphanumeric(8));
		apply.setAttach(req.getAttach());
		apply.setBody(SpringUtils.getMessage(Message.PARTNERPAY_ORDER_BODY));
		apply.setOut_trade_no(req.getOrderNo());
		apply.setTotal_fee(SettingUtils.get().setScale(new BigDecimal(req.getMoney()).multiply(new BigDecimal(100))).intValue());
		if (SettingUtils.get().getIsDebug()) {
			log.debug("=========debug环境 无感支付0.01=========");
			apply.setTotal_fee(1);
		}
		apply.setSpbill_create_ip(DeviceUtil.getInternetIp());
		apply.setNotify_url(getPayResultNotifyUrl());
		apply.setTrade_type("PAP");// 固定值
		apply.setTrade_scene(PartnerpayScene.PARKING.name());
		SceneInfo sceneInfo = new SceneInfo();
		switch (req.getScene()) {
		case PARKING:
			sceneInfo.setStart_time(req.getData().get("start_time"));
			sceneInfo.setEnd_time(req.getData().get("end_time"));
			sceneInfo.setCharging_time(req.getData().get("charging_time"));
			sceneInfo.setPlate_number(req.getData().get("plate_number"));
			sceneInfo.setParking_name(req.getData().get("parking_name"));
			break;
		default:
			throw new MyException("暂不支持的代扣场景");
		}
		apply.setScene_info(sceneInfo);
		weixin.popular.bean.vehicle.PayApplyResult result = PayVeticleAPI.payApply(apply, req.getMchKey());
		PayApplyResult resp = new PayApplyResult(Platform.weixin);
		if (result == null) {
			resp.setErrcode("SYSTEMERROR");
			resp.setMsg("网络连接中断");
		} else if (!result.isSuccess()) {
			resp.setErrcode(result.getErr_code());
			resp.setMsg(result.getReturn_msg());
		} else if (!"SUCCESS".equals(result.getResult_code())) {
			resp.setErrcode(result.getErr_code());
			resp.setMsg(result.getErr_code_des());
		} else {
			resp.setIsResultSuccess(true);
		}
		return resp;
	}

	@Override
	public JumpToSignPageResult jumpToSignPage(PartnerpayScene scene, ParkingLot lot, String path, String openid, String subOpenid, String carPlate, String channelType, String materialInfo,
			String client) {
		if (scene == PartnerpayScene.HIGHWAY && StringUtils.isEmpty(carPlate)) {
			throw new MyException("carPlate can't be null");
		}
		OemConfig oem = oemConfigService.findByParkingLot(lot.getId());
		NavigateToAppForAuth navigateToMappForAuth = PayVeticleAPI.navigateToMappForAuth(path, scene.name(), oem.getWxAppid(), oem.getWxSubAppid(), oem.getWxMchid(), oem.getWxSubMchid(),
				openid, subOpenid, carPlate, materialInfo, channelType, oem.getWxMchKey());
		JumpToSignPageResult rs = new JumpToSignPageResult();
		rs.setIsResultSuccess(true);
		Map<String, String> map = BeanUtils.jsonBean2Map(navigateToMappForAuth.getExtra_data());
		rs.setExtraData(map);
		rs.setAppId(navigateToMappForAuth.getAppId());
		rs.setPath(path);
		if ("H5".equalsIgnoreCase(client)) {
			StringBuilder url = new StringBuilder();
			if (path != null) {
				url.append(path);
				if (!path.endsWith("?")) {
					url.append("?");
				}
			}
			try {
				for (Map.Entry<String, String> e : map.entrySet()) {
					if (e.getValue() != null && e.getValue().length() > 0) {
						url.append(e.getKey()).append("=").append(URLEncoder.encode(e.getValue(), "utf-8")).append("&");
					}
				}
			} catch (UnsupportedEncodingException e1) {
			}
			url = url.deleteCharAt(url.length() - 1).append("#wechat_redirect");
			rs.setUrl(url.toString());
		}
		return rs;
	}

	@Override
	public int compareTo(PartnerpayApiService o) {
		return 0;
	}
}